//
//  WebSocketRocketManger.m
//  IMDome
//
//  Created by limaohuyu on 2020/8/13.
//  Copyright © 2020 czw. All rights reserved.
//

#import "WebSocketRocketManger.h"
#import "ShowContentModel.h"


@interface WebSocketRocketManger()<SRWebSocketDelegate>
{
     //心跳定时器
    dispatch_source_t _timer ;
    // 重连的时间间隔阶梯
    NSTimeInterval reConnectTime;
}
@property (nonatomic,strong) SRWebSocket *socket;
@property (nonatomic,copy) NSString *urlString;

@end

@implementation WebSocketRocketManger
+ (WebSocketRocketManger *)instance{
    static WebSocketRocketManger *rocketManger = nil;
     static dispatch_once_t predicate;
     dispatch_once(&predicate, ^{
         rocketManger = [[WebSocketRocketManger alloc] init];
     });
     return rocketManger;
}
-(void)openWebSocketWithURLString:(NSString *)urlString{
    //如果是同一个url 直接返回
    if (self.socket) {
        return;
    }
    if (kStringIsEmpty(urlString)) {
        return;
    }
    self.urlString = urlString;
    self.socket = [[SRWebSocket alloc] initWithURLRequest:
                   [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
    self.socket.delegate = self;   //SRWebSocketDelegate 协议
    [self.socket open];     //开始连接
}
#pragma mark  ==== SRWebSocketDelegate

//socket 连接成功
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    //每次正常连接的时候清零重连时间
     reConnectTime = 0;
    if (webSocket == self.socket) {
        NSLog(@"链接成功");
        //开启心跳任务
        [self starHearBeatPing];
        //发送初始化链接数据
        SenderContentModel*senderData = [SenderContentModel new];
        senderData.action =1;
        ContentChatModel *chatMOdel =  [ContentChatModel new];
        chatMOdel.senderId = self.senderId ;
        chatMOdel.receiveId = @"";
        chatMOdel.msg =@"第一次(或重连)初始化连接";
        senderData.chatMsg =chatMOdel;
        [self sendMessage:senderData.mj_JSONString];
     
        if (self.webSocketDidOpen) {
            self.webSocketDidOpen();
        }
        
    }
}
//socket 连接失败
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    if (webSocket == self.socket) {
        _socket = nil;
        //连接失败就重连
        [self reConnect];
    }
}
// 接收后台推送的数据
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
    
    if (webSocket == self.socket) {
        if ([self.delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)]) {
            [self.delegate webSocket:webSocket didReceiveMessage:message];
        }
        if (self.didReceiveMessage) {
            self.didReceiveMessage(message);
        }
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    if (webSocket == self.socket) {
        NSLog(@"被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
        [self closeWebSocket];
        if (self.closeWebSocketBlocl) {
            self.closeWebSocketBlocl();
        }
    }else{
        if (code == SRStatusCodeNormal ) {
            NSLog(@"主动断开链接");
        }
        
    }
}


#pragma mark === 发送数据
#define WeakSelf(ws) __weak __typeof(&*self)weakSelf = self
- (void)sendMessage:(id)message{
    WeakSelf(ws);
    dispatch_queue_t queue =  dispatch_queue_create("WBSendData", NULL);
    dispatch_async(queue, ^{
        if (weakSelf.socket != nil) {
            // 只有 SR_OPEN 开启状态才能调 send 方法啊，不然要崩
            if (weakSelf.socket.readyState == SR_OPEN) {
                [weakSelf.socket send:message];    // 发送数据
            } else if (weakSelf.socket.readyState == SR_CONNECTING) {
               //正在连接中，重连后其他方法会去自动同步数据
                /**
                 每隔2秒检测一次 socket.readyState 状态，检测 10 次左右
                 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
                 如果 10 次都还是没连上的，那这个发送请求就丢失了，这种情况是服务器的问题了，小概率的
                 代码有点长，我就写个逻辑在这里好了
                 */
                [self reConnect];
            } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
                // websocket 断开了，调用 reConnect 方法重连
                [self reConnect];
            }
        } else {
            NSLog(@"没网络，发送失败，一旦断网 socket 会被我设置 nil 的");
            NSLog(@"其实最好是发送前判断一下网络状态比较好，我写的有点晦涩，socket==nil来表示断网");
            [self reConnect];
        }
    });
}


#pragma mark == 重连机制
- (void)reConnect
{
    [self closeWebSocket];
    //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
    if (reConnectTime > 64) {
        //您的网络状况不是很好，请检查网络后重试
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.socket = nil;
        [self openWebSocketWithURLString:self.urlString];
        NSLog(@"重连");
    });
    //重连时间2的指数级增长
    if (reConnectTime == 0) {
        reConnectTime = 2;
    }else{
        reConnectTime *= 2;
    }
}


#pragma mark == 开启发送心跳任务

- (void)starHearBeatPing {
    if (self.socket.readyState == SR_OPEN) {
        if (_timer == nil) {
            [self setHearBeatPingData];
        }
    }else{
      dispatch_cancel(_timer);
      _timer = nil;
    }
 
}
#pragma mark == 创建发送心跳的定时任务

/*后台设置：
 读空闲：40s
 写空闲：60s
 读写空闲：100s
 **/
- (void)setHearBeatPingData{
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 90 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(_timer, ^{
        if (self.socket.readyState == SR_OPEN) {
            ShowContentModel *hearttModel = [ShowContentModel new];
            hearttModel.action = 4;
            [self.socket sendPing:hearttModel.mj_JSONData];
        }
    });
    dispatch_resume(_timer);

}
#pragma mark == 关闭WebSocket
-(void)closeWebSocket{
    if (self.socket){
        [self.socket close];
        self.socket = nil;
        if (_timer != nil) {
            dispatch_cancel(_timer);
            _timer = nil;
        }
    }
}
@end
